﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Brjnk.Common;
using Brjnk.Common.Extensions;
using Brjnk.GpxExplorer.ViewModel;

namespace Brjnk.GpxExplorer.Workspace
{
    internal class PhotosLoader
    {
        private DataModel data;

        private Thread workingThread;

        private AutoResetEvent evnt = new AutoResetEvent(false);

        private Dispatcher dispatcher;

        private BackgroundOperationState backgrounOperationState = new BackgroundOperationState("PhotosLoader", "workingLoadingPhotos", "empty", "empty", true);

        public PhotosLoader(DataModel data)
        {
            this.data = data;
            workingThread = new Thread(WorkingThread);
            workingThread.IsBackground = true;
            workingThread.Priority = ThreadPriority.BelowNormal;
            workingThread.Start();

            dispatcher = Dispatcher.CurrentDispatcher;

            BackgroundOperationList.Instance.Add(backgrounOperationState);
        }

        private List<string> queue = new List<string>();

        public void Load(string path)
        {
            lock (queue)
            {
                queue.Add(path);
                evnt.Set();
            }
        }

        private void WorkingThread()
        {
            while (true)
            {
                evnt.WaitOne();
                SetShortDescription(queue.Count);
                SetLongDescription(string.Empty);
                SetBackgroundOperationState(true);

                while (queue.Count > 0)
                {
                    string path;
                    lock (queue)
                    {
                        var lastIndex = queue.Count - 1;
                        path = queue[lastIndex];
                        queue.RemoveAt(lastIndex);
                        SetShortDescription(queue.Count);
                    }
                    SetLongDescription(path);
                    try
                    {
                        LoadPhoto(path);
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine("An error occured during loading photo.\n" + ex.ToString());
                    }
                }
                SetBackgroundOperationState(false);
            }
        }

        private void SetLongDescription(string path)
        {
            dispatcher.Invoke(new Action<string>(s => backgrounOperationState.SetLongInfo(s)), new object[] { path });
        }

        private void SetShortDescription(int p)
        {
            dispatcher.Invoke(new Action<int>(n => SetShortDescriptionUIThread(n)), new object[] { p });
        }

        private void SetShortDescriptionUIThread(int newCount)
        {
            var current = backgrounOperationState.Info;
            int currentCount = 0;
            if (int.TryParse(current, out currentCount) && newCount % 10 != 0)
            {
                if (currentCount < newCount)
                    backgrounOperationState.SetInfo(newCount.ToString());
            }
            else backgrounOperationState.SetInfo(newCount.ToString());
        }

        private void SetBackgroundOperationState(bool p)
        {
            dispatcher.Invoke(new Action<bool>(b => backgrounOperationState.SetState(b)), new object[] { p });
        }

        private void LoadPhoto(string path)
        {
            var photo = new Photo(new Uri(path));
            //odstranit duplikáty
            LoadThumbnail(photo);
            AddPhoto(photo);
        }

        private void LoadThumbnail(Photo photo)
        {
            double scale = Math.Min(128 / (double)photo.PixelWidth, 128 / (double)photo.PixelHeight);
            var b = new BitmapImage();
            b.BeginInit();

            var thumb = new BitmapImage();
            thumb.BeginInit();
            thumb.UriSource = new Uri(photo.FullName);
            thumb.DecodePixelHeight = (int)(photo.PixelHeight * scale);
            thumb.DecodePixelWidth = (int)(photo.PixelWidth * scale);

            thumb.EndInit();
            thumb.Freeze();
            photo.SetThumbnail(thumb);
        }

        private void AddPhoto(Photo photo)
        {
            dispatcher.Invoke(new Action<Photo>(p => AddPhotoUIThread(p)), new object[] { photo });
        }

        private void AddPhotoUIThread(Photo photo)
        {
            data.Photos.Collection.RemoveWhere(p => p.FullName == photo.FullName);
            if (!photo.Fail) data.Photos.Collection.Add(photo);
        }
    }
}